<template>
	<view class="review">
		<view class="head">
			<cover-image class="fanhui" src="/static/fanhui.png" @click="back"></cover-image>
			<text class="p" @click="back">预览</text>
		</view>
		<view class="content">
			<view class="address">
				<cover-image class="img" src="/static/positioning.png"></cover-image>
				<text class="text">{{ addressName }}</text>
			</view>
			<view v-if="options.code !== 'app_red_note'" class="one">
				第一步 点开图片 长按保存
			</view>
			<view class="img-list">
				<cover-image class="img" v-for="(item, index) in imgs" :key="item" @click="previewImage(item)" :src="item"
					@load="onImgLoad(index)" :class="{ 'img-loaded': imgLoaded[index] }"></cover-image>
			</view>
			<view class="copywriting">
				<cover-image class="arrow" src="/static/jiantou.png"></cover-image>
				<view class="copywriting-content" :class="options.code === 'app_red_note' ? 'max' : ''" ref="contentContainer">
					<up-skeleton v-show="!contentTitle && options.code === 'app_red_note'" style="margin-bottom: 20rpx;" rows="1"
						:title="false" rowsHeight="24" :loading="!contentTitle"></up-skeleton>
					<view v-show="options.code === 'app_red_note'" class="contentTitle">
						{{ contentTitle }}
					</view>
					<up-skeleton rows="3" :loading="!content">
					</up-skeleton>
					{{ content }}
					<text v-show="content && !isContentDone" class="dots">{{ dots }}</text>
					<span v-if="content && !isContentDone" class="cursor"></span>
				</view>
			</view>
			<view v-if="options.code !== 'app_red_note'" class="one three">
				第二步 打开{{ appName }} 进行评论
			</view>
			<view class="button-list">
				<view v-if="maxGenNum > 1" class="button"
					:class="[currentGenNum >= maxGenNum || !(content && isContentDone) ? 'disable' : '', options.code === 'app_red_note' ? 'equal-width' : '']"
					@click="getIndexInfo(true)">
					<view v-if="!isContentDone" class="loading-icon"></view>
					第
					{{ currentGenNum }}/{{ maxGenNum }} 条
				</view>
				<view class="button"
					:class="[!(content && isContentDone) ? 'disable' : '', maxGenNum === 1 ? 'full-width' : '', options.code === 'app_red_note' ? 'equal-width' : '']"
					@click="goToApp">
					{{ published ? '再次发布' : (options.code === 'app_red_note' ? '打开' + appName + '发布' : '复制文案并打开' + appName + '发布')	}}
				</view>
			</view>
		</view>
		<view class="tips">
			若浏览器跳转{{ appName }}失败,请手动打开{{ appName }}
		</view>
	</view>
</template>

<script>
import { channelListMap } from '../index/appList.js'

export default {
	data() {
		return {
			options: {},
			addressName: '',
			appName: '',
			imgs: [],
			currentGenNum: 1,
			maxGenNum: 3,
			published: false,
			content: '',
			dots: '',
			contentTitle: '',
			isContentDone: false,
			lastLineCount: 0,
			imgLoaded: []
		}
	},
	watch: {
		content: {
			handler() {
				this.$nextTick(() => {
					const container = this.$refs.contentContainer;
					if (container) {
						container.scrollTop = container.scrollHeight;
					}
				});
			},
			deep: true
		}
	},
	onLoad(options) {
		this.options = options
		this.getIndexInfo()
		this.donghua()
	},
	methods: {
		async getIndexInfo(isInit) {
			if ((this.currentGenNum >= this.maxGenNum || !(this.content && this.isContentDone)) && isInit) return
			this.contentTitle = ""
			this.content = ''
			this.addressName = this.options.addressName
			this.appName = channelListMap[this.options.code]
			const userNo = await this.getBrowserFingerprint()
			uni.request({
				url: '/app-api/market/ai/get',
				data: {
					storeCode: this.options.storeCode,
					channelId: this.options.channelId,
					no: isInit ? '' : (uni.getStorageSync('no') || ''),
					userNo
				},
				method: 'GET',
				success: (res) => {
					const data = res.data.data
					this.imgs = data.imageList || []
					this.imgLoaded = new Array(this.imgs.length).fill(false);
					this.currentGenNum = data.currentGenNum
					this.maxGenNum = data.maxGenNum
					this.published = data.published
					uni.setStorageSync('no', data.genNo)
					if (data.messageText) {
						this.contentTitle = data.title
						this.characterByCharacterDisplay(data.messageText)
					} else {
						this.contentIofo()
					}
				}
			});
		},
		characterByCharacterDisplay(text) {
			this.isContentDone = false
			this.content = ''
			let currentIndex = 0
			const interval = 20 // 每个字符的显示间隔，单位毫秒

			const displayNextCharacter = () => {
				if (currentIndex < text.length) {
					this.content += text[currentIndex]
					currentIndex++
					// 计算当前行数并滚动
					this.$nextTick(() => {
						const container = this.$refs.contentContainer.$el || this.$refs.contentContainer;
						if (container) {
							const lineHeight = parseInt(window.getComputedStyle(container).lineHeight);
							const contentHeight = container.scrollHeight;
							const currentLineCount = Math.floor(contentHeight / lineHeight);

							if (currentLineCount !== this.lastLineCount) {
								this.lastLineCount = currentLineCount;
								container.scrollTop = container.scrollHeight;
							}
						}
					});
					setTimeout(displayNextCharacter, interval)
				} else {
					this.isContentDone = true
				}
			}

			displayNextCharacter()
		},
		getContentTitle() {
			uni.request({
				url: '/app-api/market/ai/chat/title',
				data: {
					no: uni.getStorageSync('no'),
					message: this.content
				},
				method: 'POST',
				success: (res) => {
					this.contentTitle = res.data?.data
				}
			});
		},
		contentIofo() {
			this.isContentDone = false
			const no = uni.getStorageSync('no')
			this.content = ""; // 当前展示的文本
			this.dots = ""; // 重置省略号

			fetch('/app-api/market/ai/chat/message', {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
					'Accept': 'text/event-stream'
				},
				body: JSON.stringify({ no })
			}).then(response => {
				const reader = response.body.getReader();
				const decoder = new TextDecoder();
				const readStream = async () => {
					while (true) {
						const { done, value } = await reader.read();
						// 一旦流读取完成，启动逐字显示
						if (done) {
							this.isContentDone = true
							this.dots = ""; // 清除省略号
							if (this.options.code === 'app_red_note') { this.getContentTitle() }
							break;
						}
						const text = decoder.decode(value, { stream: true });
						// 以换行符拆分数据（SSE 数据是以 `\n\n` 结束）
						let lines = text.split("\n\n");
						// 处理完整的 SSE 消息
						for (let i = 0; i < lines.length - 1; i++) {
							let line = lines[i].trim();
							if (line.startsWith("data:")) {
								try {
									const jsonData = JSON.parse(line.slice(5)); // 去掉 `data: ` 解析 JSON
									this.content += jsonData.data.receive.content

									// 计算当前行数
									this.$nextTick(() => {
										const container = this.$refs.contentContainer.$el || this.$refs.contentContainer;
										if (container) {
											const lineHeight = parseInt(window.getComputedStyle(container).lineHeight);
											const contentHeight = container.scrollHeight;
											const currentLineCount = Math.floor(contentHeight / lineHeight);

											if (currentLineCount !== this.lastLineCount) {
												this.lastLineCount = currentLineCount;
												container.scrollTop = container.scrollHeight;
											}
										}
									});
								} catch (e) {
									console.error('JSON 解析错误:', e);
								}
							}
						}
					}
				};
				readStream();
			}).catch(error => {
				console.error('Request failed:', error);
			});
		},
		copyText() {
			if (!this.content || !this.isContentDone) return
			if (navigator?.clipboard?.writeText) {
				navigator.clipboard.writeText(this.content).catch(() => { });
			} else {
				uni.setClipboardData({
					data: this.content, // 直接复制带 `\n` 的文本
					success: () => {
						// uni.showToast({ title: '复制成功', icon: 'success' });
					}
				});
			}
		},
		back() {
			const code = uni.getStorageSync('urlCode')
			uni.navigateTo({ url: "/pages/index/index?code=" + code })
		},
		goToApp() {
			if (!this.content || !this.isContentDone) return
			// 通知后台该条评论被发布
			if (!this.published) {
				uni.request({
					url: `/app-api/market/ai/mark-published?no=${uni.getStorageSync('no')}`,
					method: 'POST',
					success: (res) => {
					}
				});
			}
			if (this.options.code !== 'app_red_note') {
				this.copyText()
			}
			if (this.options.code === 'app_red_note') {
				uni.request({
					url: '/app-api/market/channel/xhs/token',
					data: {},
					method: 'POST',
					success: (res) => {
						xhs.share({
							shareInfo: {
								type: 'normal', // 必填，笔记类型 'video' | 'normal'
								title: this.contentTitle, // 笔记标题
								content: this.content, // 笔记正文
								images: this.imgs, //图文类型必填，笔记图片，必须是服务器地址，暂时不支持本地文件
								video: '', // 视频类型必填，必须是服务器地址
								cover: '' // 视频封面图，必须是服务器地址，暂时不支持本地文件
							},
							verifyConfig: res.data.data,
							fail: (e) => {
								// 调用失败时执行的回调函数
								alert(e)
							}
						})
					}
				})
			} else {
				window.location.href = this.options.linkUrl;
			}
		},
		previewImage(current) {
			// let that = this
			uni.previewImage({
				indicator: true,
				loop: true,
				current: current,
				urls: this.imgs,
				longPressActions: {
					itemList: ['保存图片'],
					success(data) {
						// that.saveImage(imgurl)
					},
					fail: function (err) {
						console.log(err.errMsg);
					}
				}
			})
		},
		donghua() {
			let count = 0;
			setInterval(() => {
				count = (count + 1) % 4;
				this.dots = ".".repeat(count);
			}, 200);
		},
		async getBrowserFingerprint() {
			try {
				// 首先检查是否有缓存的指纹
				const cachedFingerprint = uni.getStorageSync('browserFingerprint');
				if (cachedFingerprint) {
					return cachedFingerprint;
				}

				// 收集浏览器特征
				const features = [
					navigator.userAgent || '',
					window.screen.width || '',
					window.screen.height || '',
					Intl.DateTimeFormat().resolvedOptions().timeZone || '',
					navigator.language || '',
					navigator.hardwareConcurrency || '',
					new Date().getTimezoneOffset() || '',
					window.devicePixelRatio || '',
					navigator.platform || ''
				].join('-');

				let fingerprint = '';

				// 尝试使用 crypto.subtle.digest
				if (window.crypto && window.crypto.subtle && window.crypto.subtle.digest) {
					try {
						const encoder = new TextEncoder();
						const data = encoder.encode(features);
						const hashBuffer = await crypto.subtle.digest('SHA-256', data);
						const hashArray = Array.from(new Uint8Array(hashBuffer));
						fingerprint = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
					} catch (error) {
						console.warn('Crypto API failed:', error);
					}
				}

				// 如果 crypto API 失败，使用简单的哈希函数
				if (!fingerprint) {
					let hash = 0;
					for (let i = 0; i < features.length; i++) {
						const char = features.charCodeAt(i);
						hash = ((hash << 5) - hash) + char;
						hash = hash & hash; // Convert to 32-bit integer
					}
					fingerprint = Math.abs(hash).toString(16).padStart(8, '0');

					// 添加随机字符串使其更独特
					const randomPart = Math.random().toString(36).substring(2);
					fingerprint += randomPart;
				}

				// 存储指纹以供后续使用
				uni.setStorageSync('browserFingerprint', fingerprint);
				return fingerprint;
			} catch (error) {
				console.warn('Fingerprint generation failed:', error);
				// 如果所有方法都失败，生成一个随机指纹
				const randomFingerprint = Date.now().toString(36) + Math.random().toString(36).substring(2);
				uni.setStorageSync('browserFingerprint', randomFingerprint);
				return randomFingerprint;
			}
		},
		getRandomSHA256Hex() {
			const SHA256Hex = uni.getStorageSync('SHA256Hex')
			if (SHA256Hex) return SHA256Hex
			const randomBytes = new Uint8Array(32); // 32 字节 = 256 位
			crypto.getRandomValues(randomBytes); // 生成随机字节
			const data = Array.from(randomBytes)
				.map(byte => byte.toString(16).padStart(2, '0'))
				.join('');
			uni.setStorageSync('SHA256Hex', data)
			return data
		},
		onImgLoad(index) {
			this.$set(this.imgLoaded, index, true);
		}
	}
}
</script>

<style>
.review {
	position: absolute;
	top: 0;
	left: 0;
	bottom: 0;
	right: 0;
	background: linear-gradient(180deg, #C7D8FF 0%, #FFFFFF 42%, #F5F7F9 100%);

	.head {
		display: flex;
		height: 120rpx;
		align-items: center;
		padding-left: 40rpx;

		.fanhui {
			width: 20rpx;
			height: 40rpx;
			margin-right: 21rpx;
		}

		.p {
			font-size: 42rpx;
			color: #000;
			font-weight: bold;
		}
	}

	.content {
		width: 100%;
		background: #FFFFFF;
		box-shadow: 0rpx -6rpx 20rpx 0rpx rgba(0, 0, 0, 0.12);
		border-radius: 36rpx;
		margin-top: 10rpx;
		padding: 40rpx 25rpx;
		box-sizing: border-box;

		.address {
			background: linear-gradient(270deg, #FFFFFF 0%, #E2EBFF 100%);
			border-radius: 32rpx;
			height: 64rpx;
			display: flex;
			align-items: center;
			padding: 0 26rpx;
			margin-bottom: 30rpx;

			.img {
				width: 40rpx;
				height: 45rpx;
				margin-right: 12rpx;
			}

			.text {
				font-size: 28rpx;
				color: #333333;
				font-weight: bold;
			}
		}

		.one {
			color: #333333;
			font-size: 30rpx;
			text-indent: 10rpx;
			margin-bottom: 30rpx;
			position: relative;
			font-weight: bold;
		}

		.img-list {
			width: 100%;
			display: flex;

			.img {
				width: calc((100% - 3 * 23rpx) / 4);
				aspect-ratio: 1 / 1;
				margin-right: 23rpx;
				border-radius: 10rpx;
				box-shadow: 0 8px 24px rgba(31, 100, 255, 0.18), 0 1.5px 6px rgba(0, 0, 0, 0.08);
				transition: transform 0.5s cubic-bezier(.4, 2, .6, 1), box-shadow 0.5s;
				animation: img-breath 2.8s ease-in-out infinite;
				z-index: 1;
				opacity: 0.7;
				transform: scale(0.7);
			}

			.img:first-child {
				margin-left: 11.5rpx;
			}

			.img.img-loaded {
				animation: img-pop-in 0.7s cubic-bezier(.4, 2, .6, 1);
				opacity: 1;
				transform: scale(1);
			}
		}

		.two {
			margin-top: 50rpx;
			position: relative;

			.copy {
				position: absolute;
				right: 0;
				top: -10rpx;
				background-color: #E3EBFF;
				color: #1F64FF;
				padding: 15rpx 20rpx 15rpx 15rpx;
				border-radius: 30rpx;
				cursor: pointer;
				font-size: 24rpx;
			}

			.disable {
				background-color: #f2f2f2;
				color: #b1b1b1;
			}
		}

		.copywriting {
			position: relative;
			margin-top: 30rpx;

			.arrow {
				width: 46rpx;
				height: 25rpx;
				position: relative;
				left: 60rpx;
			}
		}

		.copywriting-content {
			background: linear-gradient(135deg, #eaf1ff 0%, #f6f6f8 100%);
			border-radius: 36rpx;
			box-shadow: 0 4px 24px rgba(31, 100, 255, 0.08);
			padding: 40rpx 36rpx;
			font-size: 30rpx;
			font-weight: 500;
			line-height: 1.8;
			min-height: 340rpx;
			position: relative;
			overflow: auto;
			max-height: 420rpx;

			.dots {
				color: #8f8f8f;
				font-size: 26rpx;
				margin-left: 4rpx;
				animation: fadeInOut 1.5s infinite;
				display: inline-block;
				vertical-align: middle;
				line-height: 1.5;
				width: 60rpx;
				height: 42rpx;
				text-align: left;
				visibility: hidden;
			}

			.dots:not(:empty) {
				visibility: visible;
			}

			@keyframes fadeInOut {
				0% {
					opacity: 0.3;
				}

				50% {
					opacity: 1;
				}

				100% {
					opacity: 0.3;
				}
			}

			.contentTitle {
				font-size: 28rpx;
				font-weight: bold;
				color: #000;
				margin-bottom: 10rpx;
			}
		}

		.max {
			height: 570rpx;
		}

		.three {
			margin-top: 50rpx;
		}

		.button-list {
			width: 100%;
			display: flex;
			justify-content: space-around;
			margin-top: 60rpx;

			.button {
				height: calc((100% - 40rpx) / 2);
				background: linear-gradient(90deg, #6ea8ff 0%, #1F64FF 100%);
				color: #fff;
				text-align: center;
				padding: 25rpx 0;
				border-radius: 60rpx;
				font-size: 32rpx;
				font-weight: bold;
				display: flex;
				align-items: center;
				justify-content: center;
				position: relative;
				box-shadow: 0 4px 16px rgba(31, 100, 255, 0.12);
				transition: background 0.3s;

				&:first-child {
					width: calc((100% - 40rpx) / 3);
				}

				&:last-child {
					width: calc((100% - 40rpx) * 2 / 3);
				}

				&.equal-width {
					width: calc((100% - 40rpx) / 2) !important;
				}

				&.full-width {
					width: 100%;
				}

				.loading-icon {
					width: 40rpx;
					height: 40rpx;
					margin-right: 30rpx;
					position: relative;
					margin-left: -10rpx;
				}

				.loading-icon::before,
				.loading-icon::after {
					content: '';
					position: absolute;
					width: 100%;
					height: 100%;
					border-radius: 50%;
					background-color: currentColor;
					opacity: 0.6;
					animation: pulse 2s ease-in-out infinite;
				}

				.loading-icon::after {
					animation-delay: -1s;
				}
			}

			.disable {
				background: #e0e0e0;
				color: #b1b1b1;
			}
		}
	}

	.tips {
		font-weight: 400;
		font-size: 24rpx;
		color: #6ea8ff;
		text-align: left;
		margin: 40rpx;
		box-sizing: border-box;
		padding-left: 32rpx;
		position: relative;
	}

	.tips:before {
		content: '\1F4A1';
		display: inline-block;
		margin-right: 12rpx;
		font-size: 28rpx;
		vertical-align: middle;
	}
}

@keyframes pulse {
	0% {
		transform: scale(0);
		opacity: 0.6;
	}

	50% {
		transform: scale(1);
		opacity: 0.2;
	}

	100% {
		transform: scale(0);
		opacity: 0.6;
	}
}

@keyframes img-breath {
	0% {
		transform: scale(1);
	}

	50% {
		transform: scale(1.04);
	}

	100% {
		transform: scale(1);
	}
}

@keyframes img-pop-in {
	0% {
		transform: scale(0.7);
		opacity: 0.5;
	}

	60% {
		transform: scale(1.12);
		opacity: 1;
	}

	80% {
		transform: scale(0.95);
	}

	100% {
		transform: scale(1);
	}
}

.cursor {
	display: inline-block;
	width: 6rpx;
	height: 1.2em;
	background: #1F64FF;
	margin-left: 6rpx;
	animation: blink 1s steps(1) infinite;
	vertical-align: middle;
	border-radius: 2rpx;
}

@keyframes blink {

	0%,
	50% {
		opacity: 1;
	}

	51%,
	100% {
		opacity: 0;
	}
}
</style>